﻿// Copyright (c) egmkang wang. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace XServer.Grains
{
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Orleans;
    using Orleans.Concurrency;
    using GrainInterfaces;
    using SDK;
    using XServer.Message;
    using XServer.Record;


    class RankItemInfoCompareV1 : IComparer<RankItemInfo>
    {
        public int Compare(RankItemInfo x, RankItemInfo y)
        {
            return y.V1.CompareTo(x.V1);
        }
    }

    [Reentrant]
    public class RankGrain : Grain, IRankGrain
    {
        MsgRspLoadRankList response = new MsgRspLoadRankList();
        List<RankItemInfo> items = new List<RankItemInfo>();
        //ServerID_RankType_MaxCount
        long serverID = 0;
        int type = 0;
        int maxCount = 0;
        IComparer<RankItemInfo> cmp = null;

        void InitParam()
        {
            var key = this.GetPrimaryKeyString();
            var array = new StringView(key).Split('_');
            if (array.Length != 3)
            {
                throw new ArgumentException(String.Format("RankGrain's PrimaryKey error:{0}", key));
            }
            this.serverID = array[0].ToInt64();
            this.type = array[1].ToInt32();
            this.maxCount = array[2].ToInt32();
            this.cmp = new RankItemInfoCompareV1();
        }

        async Task LoadDataFromDB()
        {
            var list = await MysqlUtils.LoadRankItem(this.serverID, this.type, this.maxCount);
            this.items.Clear();
            this.items.AddRange(list);
        }

        async Task SaveToDB(RankItemInfo info, bool delete_all)
        {
            if (delete_all)
            {
                this.items.Clear();
                await MysqlUtils.ClearRankItem(this.serverID, this.type);
            }
            else if (info != null)
            {
                await MysqlUtils.SaveRankItem(this.serverID, this.type, info);
            }
        }

        public async override Task OnActivateAsync()
        {
            this.InitParam();
            await this.LoadDataFromDB();
            await base.OnActivateAsync();
        }

        public override Task OnDeactivateAsync()
        {
            return base.OnDeactivateAsync();
        }

        public async Task Clear()
        {
            this.items.Clear();
            await this.SaveToDB(null, true);
        }

        public Task<List<RankItemInfo>> GetAllData()
        {
            return Task.FromResult(this.items);
        }

        public Task<int> GetRank(long playerID)
        {
            int rank = 0;
            foreach (var item in this.items)
            {
                rank++;
                if (item.Uid == playerID)
                {
                    return Task.FromResult(rank);
                }
            }
            return Task.FromResult(0);
        }

        public async Task<KeyValuePair<int, int>> UpdatePlayerInfo(RankItemInfo item)
        {
            int oldRank = await GetRank(item.Uid);
            if (oldRank > 0)
            {
                this.items[oldRank - 1] = item;
            }
            else
            {
                this.items.Add(item);
            }

            this.items.Sort(this.cmp);
            while (this.items.Count > this.maxCount)
            {
                this.items.RemoveAt(this.items.Count - 1);
            }
            int newRank = await GetRank(item.Uid);
            await this.SaveToDB(item, false);
            return new KeyValuePair<int, int>(oldRank, newRank);
        }

        public async Task Remove(long playerID)
        {
            int rank = await this.GetRank(playerID);
            if (rank > 0)
            {
                var item = this.items[rank - 1];
                this.items.RemoveAt(rank - 1);
                await this.SaveToDB(item, false);
            }
        }

        public Task<int> GetPlayerCount()
        {
            return Task.FromResult(this.items.Count);
        }
    }
}
